package com.peng.consistenthash;

import com.google.common.base.Joiner;

import java.util.*;

/**
 * SortedMapVirtualNodeBalancer
 *
 * @author: lupeng10
 * @create: 2023-04-18 19:37
 */
@SuppressWarnings("UnstableApiUsage")
public class SortedMapVirtualNodeBalancer implements LoadBalancer {

    private int virtualNodeSize;

    private TreeMap<Integer, String> treeMapHash;

    public SortedMapVirtualNodeBalancer(int virtualNodeSize) {
        this.virtualNodeSize = virtualNodeSize;
        this.treeMapHash = new TreeMap<>();
    }

    @Override
    public void deleteServerNode(String serverNodeName) {
        for (int i = 0; i < virtualNodeSize; i++) {
            String virtualNode = Joiner.on("&&VN").join(serverNodeName, i);
            treeMapHash.remove(GetHashCode.getHashCode(virtualNode));
        }
    }

    @Override
    public void addServerNode(String serverNodeName) {
        for (int i = 0; i < virtualNodeSize; i++) {
            String virtualNode = Joiner.on("&&VN").join(serverNodeName, i);
            treeMapHash.put(GetHashCode.getHashCode(virtualNode), serverNodeName);
        }
    }

    @Override
    public String selectServerNode(String requestAddress) {
        int key = GetHashCode.getHashCode(requestAddress);
        Map.Entry<Integer, String> entry = treeMapHash.ceilingEntry(key);
        Map.Entry<Integer, String> finalEntry = entry == null ? treeMapHash.firstEntry() : entry;
        return finalEntry.getValue();
    }

    public void a1() {
        List<Map.Entry<Integer, String>> list = new ArrayList<>(treeMapHash.entrySet());
        list.sort(Comparator.comparingInt(Map.Entry::getKey));

        Map<String, Long> serverNode2SlotCountMap = new HashMap<>();

        for (int i = 0; i < list.size() - 1; i++) {
            Map.Entry<Integer, String> entry = list.get(i);
            serverNode2SlotCountMap.put(list.get(i + 1).getValue(), serverNode2SlotCountMap.getOrDefault(entry.getValue(), 0L) + list.get(i + 1).getKey() - entry.getKey());
        }

        long maxSlot = 4294967296L;
        long l = maxSlot - list.get(list.size() - 1).getKey() + list.get(0).getKey();
        serverNode2SlotCountMap.put(list.get(0).getValue(), l);

        Long count = serverNode2SlotCountMap.values().stream().reduce(Long::sum).get();
        System.out.println(count / serverNode2SlotCountMap.size());
    }
}
